home *** CD-ROM | disk | FTP | other *** search
- {$B-,V-,X+}
- UNIT nwIPX;
-
- {$DEFINE ProtMode}
- {$IFDEF MSDOS} {$UNDEF ProtMode} {$DEFINE RealMode} {$ENDIF}
- {$IFDEF ProtMode} sorry, protected mode not supported (yet) {$ENDIF}
-
- { nwIPX unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
-
- INTERFACE
-
- Uses Dos,nwMisc;
-
- { Primary IPX calls: Subf: Comments:
-
- IPXCancelEvent 6 AES
- * IPXCloseSocket 1 (1)
- IPXDisconnectFromTarget B (1)
- * IPXGetInterNetworkaddress 9
- * IPXGetIntervalMarker 8
- * IPXGetLocalTarget 2
- - IPXGetPacketSize D (IPX internal use only)
- * IPXInitialize INT 2F
- - IPXInitializeNetworkAddress C (IPX internal use only)
- * IPXListenForPacket 4
- * IPXOpenSocket 0
- * IPXRelinquishControl A
- * IPXScheduleIPXEvent 5 AES
- IPXScheduleSpecialEvent 7
- * IPXSendPacket 3
- - IPXTerminateSockets E (IPX internal use only)
-
- Secondary calls:
-
- * IPXpresent
- * IPXsetupSendECB
- * IPXsetupListenECB
-
- Notes: (1) These functions use INT 21 and are not to be called from
- within an ESR.
- }
-
- CONST
- LONG_LIVED_SOCKET = TRUE; { IPXopenSocket }
- SHORT_LIVED_SOCKET = FALSE;
-
- {*** PACKET TYPES ***}
-
- UNKNOWN_PACKET_TYPE =0; { (basic) Unknown IPX packet }
- IPX_PACKET_TYPE =0;
- RIP_PACKET_TYPE =1; { Routing Information Packet }
- ECHO_PACKET_TYPE =2;
- ERROR_PACKET_TYPE =3;
- PEP_PACKET_TYPE =4; { Packet Exchange Protocol }
- SPX_PACKET_TYPE =5; { Sequenced Packet Protocol Packet }
- PUP_PACKET_TYPE =12;
- DOD_IP_PACKET_TYPE =13; { Internet Protocol packet Type }
- NCP_PACKET_TYPE =17; { NetWare Core Protocol }
- { Experimental packet types: 20 - 37 }
-
- {*** SOCKET NUMBERS ***}
-
- {0001-0BB8 Registered with Xerox }
- SKT_XEROX_ROUTING_INFORMATION= $0001;
- SKT_ECHO_PROTOCOL = $0002;
- SKT_ERROR_HANDLER = $0003;
-
- {0020-003F Xerox : Experimental }
- SKT_NW4_TIME_SYNC_SERVER = $0040; { used by OT_NW4_TIME_SYNC_SERVER }
- SKT_FILE_SERVICE = $0451; { see also $8140, used by OT_RSPCX_SERVER }
- SKT_SERVICE_ADVERTISING = $0452; { SAP }
- SKT_ROUTING_INFORMATION = $0453; { Novell's RIP Socket }
- SKT_NETBIOS = $0455;
- SKT_DIAGNOSTIC = $0456;
- { 0457h ??? (appears to be related to server serial numbers) }
-
- {0BB9-FFFF Xerox : Dynamically assignable Sockets }
- {0BB9-3FFF Novell: }
- SKT_NMA_AGENT =$2F90; { used by OT_NMA_AGENT (NMS) }
-
- {4000-7FFF Novell: Dynamically assignable Sockets }
- { Use a socket in this range for your own applications. }
- { To avoid conflicts with other programs, you are advised NOT }
- { to use sockets numbers where the hi-byte equals the low-byte, }
- { C programmers mostly use those to avoid byte-order swapping. }
-
- { ! See the SKT_XXX file in the XIPX archive for the latest info
- on socket numbers... }
-
- {8000-FFFF Novell: Well known sockets, registered with Novell. }
- SKT_EMAIL_CHAT =$8055; { Niche Corp. }
- SKT_EMAIL_CHAT_2 =$8056; { Niche Corp. }
- SKT_BTRIEVE =$8058;
- SKT_BTRIEVE_2 =$8059;
- SKT_NW_SQL =$805A;
- SKT_NW_SQL_2 =$805B;
- SKT_GAMESERVER =$805C;
- SKT_GAMESERVER_2 =$805D;
- SKT_PRINT_SERVER =$8060;
- SKT_DIGITAL_CHAT =$806C; { Digital Inc. }
- SKT_NW_ACCESS_SERVER =$806F;
- SKT_OXXI_EMAIL_CHAT =$80C3; { Oxxi Inc. }
- SKT_PRINT_SERVER_2 =$811E;
- SKT_INTEL_EMAIL_CHAT =$845F; { Intel Corp. }
- SKT_WINDOWS_EMAIL_CHAT =$9017;
- SKT_JOB_SERVER =$9022;
-
- Var Result:word; { unit errorcode variable }
-
- Type TipxHeader=Record
- checksum :word; { not used, set to $FFFF }
- length :word; { total number of bytes }
- TransportControl :byte; { used by bridges: low 4 bits= hop count }
- packetType :byte; { ignored by IPX, used by higher level
- protocols only. $00=unknown packet type}
- destination,
- source :TinternetWorkAddress;
- { if dest.network equals 0; dest
- assumed on same network as sender }
- { if dest.node =$FFFFFFFFFFFF, packet
- will be sent to all nodes. }
- end;
- { Fields within IPX and SPX are high-low. Byte swapping will be done
- by the IPX functions, except network and node addresses. }
-
- Tfragment=record { address and size of buffer fragment. }
- Address:Pointer;
- Size:word;
- end;
-
- Tecb=record
- Linkaddress :Pointer; { used by IPX itself }
- ESRaddress :Pointer;
- InUseFlag :Byte; { reset to $00 when request completed }
- CompletionCode :Byte; { valid after InUseFlag becomes $00;
- completionCode=$00: packet sent/received. }
- SocketNumber :word;
- IPXworkspace :array[1..4] of byte;
- DriverWorkspace :array[1..12] of byte;
- Immediateaddress:Tnodeaddress; { 6 bytes }
- FragmentCount :word; { must be >0 }
- Fragment :array[1..2] of Tfragment; { [1..FragmentCount] }
- { The number of fragments is unlimited.
- However, most applications use 1 or 2. }
- end;
- Tpecb=^Tecb;
-
- { TAESecb=:
- Offset Size Description
- 00h DWORD Link
- 04h DWORD ESR address
- 08h BYTE in use flag (see below)
- 09h 5 BYTEs AES workspace }
-
- Function IpxPresent:boolean;
- { Determines if an IPX driver is loaded. Calls IPXInitialize. }
-
- Function IPXinitialize:Boolean;
- { Determines if an IPX driver is loaded. }
-
- {IPX/SPX: 09h}
- Function IPXGetInternetworkAddress(Var Address:TinterNetworkAddress):boolean;
- { This call returns the network and node address of the requesting workstation. }
- { The two byte socketnumber must be appended to the end to form a full }
- { 12-Byte network address. The socketnumber will be set to 0000, indicating
- that it has to be filled later with a meaningfule number. }
-
- {IPX/SPX: 00h}
- Function IPXOpenSocket(Var socket:word; PermanentSocket:boolean):boolean;
- { When an application wants to send or receive packets on a socket,
- it should first open the socket. PermanentSocket should be set to TRUE
- if the socket is used by a TSR. This way, the socket will only be
- closed when the IPXcloseSocket function is called. Otherwise, set to FALSE. }
-
- {IPX/SPX: 01h}
- Function IPXCloseSocket(socket:word):boolean;
- { Closes the socket. TSRs should close permanent sockets before terminating. }
-
- {IPX/SPX: 02h}
- Function IPXGetLocalTarget(Address:TinternetworkAddress;
- Var ImmAddr:TnodeAddress;
- Var Ticks:word ):boolean;
- { Returns the nodeaddress (Immediate address) of a bridge/router that
- connects the senders' network with the target-network. If the target
- lies within the same network as the sender, the returned node address
- is the same as the target node-address. }
-
- {IPX/SPX: 03h}
- Function IPXSendPacket(Var Ecb:Tecb):boolean;
- { After calling this function, control is immediately turned back to the
- calling process, whilst in the background the IPX driver is trying to
- send the packet. To check if the message has been sent, check the
- ECB.InUseFlag or use a SendESR.
- The ecb must be filled with appropriate values before calling this function,
- the socket to send on must be open. }
-
- {IPX/SPX: 0Fh}
- Function IPXInternalSendPacket(Var Ecb:Tecb):boolean;
-
- {IPX/SPX: 04h}
- Function IPXListenForPacket(Var Ecb:Tecb):Boolean;
- { After calling this function, control is immediately turned back to the
- calling process. The IPX driver will wait in the background for a packet
- to be received. To check if a message has been received, check the
- ECB.InUseFlag or use a ListenESR.
- The ecb must be filled with appropriate values before calling this function,
- the socket to receive on must be open. }
-
- {IPX/SPX: 0Ah}
- Function IPXrelinquishControl:boolean;
- { Temporarily gives away CPU time to bakcground processes. This call
- improves efficeincy by informing the IPX driver that the CPU is
- available. }
-
- {IPX/SPX: 08h}
- Function IPXgetIntervalMarker(Var ticks:word):boolean;
- { Gets a time marker from IPX. The difference between two known
- time-markers can be used to determine if a timeout has occurred.
- 1 Tick = 1/18.2 second. }
-
- {IPX/SPX: 06h}
- Function IPXcancelEvent(ECB:Tecb):boolean;
- { AES call: Cancel an event.
- When the event is canceled, the ECB.InUseFlag will be set to $00 and the
- ECB.CompletionCode to $FC: Event Canceled. }
-
- {IPX/SPX: 0Bh}
- Function IPXdisconnectFromTarget(Address:TinternetworkAddress):boolean;
- { Informs the listening socket at the specified adress that no more
- packets will be sent to the listening socket.
- This function is not required in your application, it is merely used
- to inform some drivers that the connection (if any) has ended. }
-
- {IPX/SPX: 05h}
- Function IPXscheduleIPXevent(ticks:word;Var ECB:Tecb):boolean;
- { AES call: schedule an event.
- After calling this function, control is immediately turned back to the
- calling process. After waiting the number of ticks specified
- (1 tick= 1/18.2 sec.), the IPX driver activates the ECB.
- This function should never be called with an ECB that is still in use
- by the IPXdriver (i.e. ECB.InUseFlag should be 0 before calling)
- }
-
- {UPX: 0007}
- Function IPXscheduleSpecialEvent(ticks:word;Var ECB:Tecb):boolean;
-
- Procedure IpxSpxSystemCall(Var regs:registers);
- { Provides an entry into the INT A7 interrupt handler;
- Valid only if IPXinitialize or IPXinstalled were called previously. }
-
- {************** Secondary Procedures ***************************************}
-
- Procedure IPXSetupListenECB(ESRptr:Pointer; ReceiveSocket:word;
- BufPtr:Pointer; BufSize:word;
- {out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
- { Clears IPXheader and ECB, sets values of the required fields within
- the ecb and IPX header. }
-
- Procedure IPXsetupSendECB(ESRptr:pointer; SourceSocket:Word;
- DestAddr:TinterNetworkAddress;
- BufPtr:pointer; BufSize:word;
- {out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
- { Clears IPXheader and ECB, sets values of the required fields within
- the ecb and IPX header. }
-
- IMPLEMENTATION {==============================================================}
-
- CONST
- IPX_MAX_DATA_LENGTH =546;
-
- Var IpxSpxCall:Procedure;
-
- Procedure IpxSpxSystemCall(Var regs:registers); assembler;
- { This method of calling IPX/SPX is preferred by Novell. }
- { For what its' worth: this call is 48 bytes longer than the other one.. }
- asm
- { check if IpxSpxCall known. If not, return error $FF in fake AL }
- xor ah,ah
- mov al,$FF
- les di,IpxSpxCall
- mov bx,es
- cmp bx,$0000
- je @1
- { move fake regs registers to 'real' registers }
- { AX, BX, CX, DX, SI, DI, ES only. }
- les di,regs
- mov ax,es:[di+16]
- push ax { push new es }
- mov ax,es:[di+12]
- push ax { push new di }
- mov ax,es:[di]
- mov bx,es:[di+2]
- mov cx,es:[di+4]
- mov dx,es:[di+6]
- mov si,es:[di+10]
- pop di
- pop es
- { farr call to A7 interrup handler }
- push bp
- CALL IpxSpxCall
- pop bp
- @1: { move 'real' registers to fake regs registers }
- push es
- push di
- les di,regs
- mov es:[di],ax
- mov es:[di+2],bx
- mov es:[di+4],cx
- mov es:[di+6],dx
- mov es:[di+10],si
- pop ax { ax:= 'di' }
- mov es:[di+12],ax
- pop ax { ax:= 'es' }
- mov es:[di+16],ax
- end;
-
- Function IPXinitialize:Boolean;
- CONST DOS_MULTIPLEX =$2F;
- Var regs:registers;
- begin
- Regs.AX:=$7A00;
- INTR(DOS_MULTIPLEX,Regs);
- if regs.AL<>$FF
- then begin
- Result:=IPX_NOT_INSTALLED;
- IpxInitialize:=false
- end
- else begin
- @IpxSpxCall:=Ptr(Regs.es,Regs.di);
- Result:=0;
- IpxInitialize:=true;
- end;
- end;
-
- Function IpxPresent:boolean;
- begin
- IpxPresent:=IpxInitialize
- end;
-
- {IPX: 09h}
- Function IPXGetInternetworkAddress(Var Address:TinterNetworkAddress):boolean;
- { This call returns the network and node address of the requesting workstation. }
- { The two byte socketnumber must be appended to the end to form a full }
- { 12-Byte network address. }
- Var regs:registers;
- begin
- regs.bx:=$0009;
- regs.es:=seg(Address);
- regs.si:=ofs(Address);
- IpxSpxSystemCall(Regs);
- result:=regs.al;
- address.socket:=$0000; { unknown, to be set later. }
- if result<>$FF
- then result:=$00;
- IPXGetInternetworkAddress:=(result=$00);
- { possible resultcodes: $00 Successful; $FF IPX not initialized }
- end;
-
- {IPX: 00}
- Function IPXOpenSocket(Var socket:word; permanentSocket:boolean):boolean;
- Var regs:registers;
- reqForSocket:boolean;
- begin
- regs.bx:=$0000;
- if permanentSocket
- then regs.al:=$FF
- else regs.al:=$00;
- regs.dx:=swap(socket); {hi-lo}
- reqForSocket:=(socket=$0000);
-
- IpxSpxSystemCall(Regs);
-
- result:=regs.al;
- if reqForSocket
- then socket:=swap(regs.dx); {force lo-hi}
- IPXopenSocket:=(result=0);
- { resultcodes: $00 successful; $FE Socket Table Is Full;
- $FF socket already open OR IPX not initilazed. }
- end;
-
- {IPX: 01}
- Function IPXCloseSocket(socket:word):boolean;
- Var regs:registers;
- begin
- regs.bx:=$01;
- regs.dx:=swap(socket);
- IpxSpxSystemCall(regs);
- result:=regs.al;
- if result<>$FF then result:=$00;
- IPXCloseSocket:=(result=$00);
- { possible resultcodes: $00 Successful; $FF IPX not initialized }
- end;
-
-
- {IPX: 02}
- Function IPXGetLocalTarget(Address:TinternetworkAddress;
- Var ImmAddr:TnodeAddress;
- VAR ticks:Word ):boolean;
- { Ticks = estimated transmission time, in number of ticks (1/18 sec) }
- Var reqAddr:TinternetworkAddress;
- repNode:TnodeAddress;
- Regs :registers;
- begin
- move(Address,reqAddr,10);
- reqAddr.socket:=swap(Address.socket); {hi-lo}
- With regs
- do begin
- bx:=$0002;
- es:=seg(reqAddr); si:=ofs(reqAddr); di:=ofs(repNode);
- IpxSpxSystemCall(regs);
- ticks:=regs.cx;
- result:=regs.al;
- if result=0
- then move(repNode,ImmAddr,6);
- end;
- IPXGetLocalTarget:=(result=$00);
- { resultcodes: $00 Successful; $FA No path to destination node found;
- $FF IPX not initialized. }
- end;
-
- Function IPXSendPacket(Var Ecb:Tecb):boolean;
- { the ecb must be filled, before calling this function }
- { Right after this call, IPXrelinquishControl should be called Iteratively,
- this allows the sending of the IPX packet. }
- Var regs:Registers;
- begin
- regs.bx:=$0003;
- regs.es:=seg(ecb);
- regs.si:=ofs(ecb);
- IpxSpxSystemCall(Regs);
- result:=regs.al;
- if result<>$FF then result:=$00;
- IpxSendPacket:=(result=$00);
- { possible resultcodes: $00 Successful; $FF IPX not initialized }
- end;
-
-
- Function IPXInternalSendPacket(Var Ecb:Tecb):boolean;
- Var regs:Registers;
- begin
- regs.bx:=$000F;
- regs.es:=seg(ecb);
- regs.si:=ofs(ecb);
- IpxSpxSystemCall(Regs);
- result:=regs.al;
- if result<>$FF then result:=$00;
- IpxInternalSendPacket:=(result=$00);
- { possible resultcodes: $00 Successful; $FF IPX not initialized }
- end;
-
-
- Function IPXListenForPacket(Var Ecb:Tecb):Boolean;
- { socket must be opened, ECB (partly) filled. }
- Var regs:Registers;
- begin
- regs.bx:=$0004;
- regs.es:=seg(ecb);
- regs.si:=ofs(ecb);
- IpxSpxSystemCall(Regs);
- result:=regs.al;
- if result<>$FF
- then result:=$00;
- IpxListenForPacket:=(result=$00);
- {resultcodes: $00 Successful;
- $FF Listening Socket doesn't exist OR IPX not initialized }
- end;
-
- Function IPXrelinquishControl:boolean;
- Var regs:Registers;
- begin
- regs.bx:=$000A;
- IpxSpxSystemCall(Regs);
- result:=regs.al;
- if result<>$FF then result:=$00;
- IpxrelinquishControl:=(result=$00);
- {resultcodes: $00 Successful; $FF IPX not initialized }
- end;
-
- Function IPXgetIntervalMarker(Var ticks:word):boolean;
- Var regs:Registers;
- begin
- regs.bx:=$0008;
- IpxSpxSystemCall(Regs);
- ticks:=regs.ax;
- result:=$00;
- IPXgetIntervalMarker:=True;
- end;
-
- Function IPXcancelEvent(ECB:Tecb):boolean;
- Var regs:registers;
- begin
- regs.bx:=$0006;
- regs.es:=seg(ecb);
- regs.si:=ofs(ecb);
- IpxSpxSystemCall(Regs);
- result:=regs.al;
- IPXcancelEvent:=(result=0);
- { resultcodes: 00 Successful; F9 ECB cannot be canceled;
- FF ECB not in use OR IPX not initialized. }
- end;
-
- Function IPXdisconnectFromTarget(Address:TinternetworkAddress):boolean;
- VAR regs:registers;
- LocAddr:TinternetworkAddress;
- begin
- move(Address,LocAddr,10);
- LocAddr.socket:=swap(Address.socket);
- regs.bx:=$000B;
- regs.es:=seg(LocAddr);
- regs.si:=ofs(LocAddr);
- IpxSpxSystemCall(Regs);
- result:=regs.al;
- if result<>$FF
- then result:=$00;
- IPXdisconnectFromTarget:=(result=0);
- {resultcodes: $00 Successful; $FF IPX not initialized }
- end;
-
- Function IPXscheduleIPXevent(ticks:word;Var ECB:Tecb):boolean;
- Var regs:registers;
- begin
- regs.bx:=$0005;
- regs.ax:=ticks;
- regs.es:=seg(ECB);
- regs.si:=ofs(ECB);
- IpxSpxSystemCall(Regs);
- if result<>$FF
- then result:=$00;
- IPXscheduleIPXevent:=(result=0);
- {resulcodes: 00 successful; FF IPX not initialized }
- end;
-
- Function IPXscheduleSpecialEvent(ticks:word;Var ECB:Tecb):boolean;
- Var regs:registers;
- begin
- regs.bx:=$0007;
- regs.ax:=ticks;
- regs.es:=seg(ECB);
- regs.si:=ofs(ECB);
- IpxSpxSystemCall(Regs);
- if result<>$FF
- then result:=$00;
- IPXscheduleSpecialEvent:=(result=0);
- {resulcodes: 00 successful; FF IPX not initialized }
- end;
-
- {************** Secondary Procedures ***************************************}
-
- Procedure IPXSetupListenECB(ESRptr:Pointer;ReceiveSocket:word;
- BufPtr:Pointer;BufSize:word;
- {out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
- { Clears IPXheader and ECB, sets values of the required fields within
- the ecb and IPX header. }
- { ECB: ESR adress field, socket number, fragment count, frag.descriptor fields }
- begin
- FillChar(ecb,SizeOf(Tecb),#0);
- FillChar(ipxHdr,SizeOF(TipxHeader),#0);
- WITH ECB
- do begin
- if ESRptr<>NIL
- then ESRaddress:=ESRptr;
- Fragmentcount:=2;
- socketNumber:=swap(ReceiveSocket); {hi-lo}
-
- Fragment[1].Address:=@ipxHdr;
- Fragment[2].Address:=BufPtr;
- Fragment[1].size:=SizeOf(Tipxheader);
- Fragment[2].size:=BufSize;
- end;
- end;
-
- Procedure IPXsetupSendECB(ESRptr:pointer; SourceSocket:word;
- DestAddr:TinterNetworkAddress;
- BufPtr:pointer; BufSize:word;
- {out:} Var IpxHdr:TipxHeader; Var ecb:Tecb);
- { Clears IPXheader and ECB, sets values of the required fields within
- the ecb and IPX header. }
- Var ImmAddr:TnodeAddress;
- Ticks:word;
- begin
- fillchar(ipxHdr,SizeOf(TipxHeader),#0);
- with ipxhdr
- do begin
- PacketType:=IPX_PACKET_TYPE;
- Move(DestAddr,Destination,10);
- destination.socket:=swap(DestAddr.socket); {hi-lo}
- end;
- IPXGetLocalTarget(DestAddr,ImmAddr,Ticks);
- fillchar(ecb,sizeOf(ecb),#0);
- With ecb
- do begin
- if ESRptr<>NIL
- then ESRaddress:=ESRptr;
- socketNumber:=swap(SourceSocket); {hi-lo}
- Move(ImmAddr,ImmediateAddress,6);
- FragmentCount:=2;
- fragment[1].Address:=@ipxhdr;
- fragment[1].size:=SizeOf(TipxHeader);
- fragment[2].Address:=BufPtr;
- fragment[2].size:=BufSize;
- end;
- end;
-
-
-
- end.
-